package icasue.base.touch;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.*;
import org.springframework.core.env.Environment;
import org.springframework.util.StringValueResolver;

import java.util.Arrays;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author: Qiao Hang
 * @CreateDate: 2020/11/17 下午4:12
 * @UpdateDate:
 * @Description:
 */
public class ApplicationTouch implements Touch, BeanFactoryAware, ApplicationContextAware, EnvironmentAware,
        InitializingBean, ApplicationListener<ApplicationStartedEvent>, EmbeddedValueResolverAware {

    public static BeanFactory beanFactory;
    public static ApplicationContext applicationContext;
    public static StringValueResolver valueResolver;
    public static Environment environment;
    public static volatile Boolean canInvoke = Boolean.FALSE;
    public static final Map<Class, Object> strongerProxyOriginRef = new ConcurrentHashMap<Class,Object>(1<<4){

        private void knifeMapping(Class cls, Object instance){
            Object[] knifeBuffer = Optional.ofNullable((Object[]) super.get(cls)).orElse(new Object[0]);
            for (Object unit : knifeBuffer) {
                if(unit.equals(instance))
                    return;
            }
            Object[] newBuffer = Arrays.copyOf(knifeBuffer, knifeBuffer.length + 1);
            newBuffer[newBuffer.length - 1] = instance;
            super.put(cls, newBuffer);
        }

        @Override
        public Object put(Class sourceClass, Object value) {
            if(sourceClass == null)
                throw new RuntimeException("Map's key not be null.");
            Object returnVal = super.get(sourceClass);
            //retain one interface, all super class.
            if(sourceClass.isInterface()){
                knifeMapping(sourceClass,value);
            }else {
                for (Class superclass = sourceClass; superclass != null && !superclass.equals(Class.class) ; superclass = superclass.getSuperclass()){
                    knifeMapping(superclass, value);
                }
                Class[] interfaces = sourceClass.getInterfaces();
                if(interfaces.length > 0){
                    knifeMapping(interfaces[0], value);
                }
            }
            return returnVal;
        }
    };

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        ApplicationTouch.beanFactory = beanFactory;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        ApplicationTouch.applicationContext = applicationContext;
    }

    @Override
    public void setEnvironment(Environment environment) {
        ApplicationTouch.environment = environment;
    }

    @Override
    public void afterPropertiesSet() {
        // ---
    }

    @Override
    public void onApplicationEvent(ApplicationStartedEvent event) {
        ApplicationTouch.canInvoke = Boolean.TRUE;
    }

    public static Boolean ready(){
        while (!ApplicationTouch.canInvoke) {}
        return true;
    }

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        ApplicationTouch.valueResolver = resolver;
    }
}
